Clover icon

compiler

  1. Project Clover database Mon Jan 2 2023 15:09:37 MST
  2. Package com.google.javascript.jscomp

File DefinitionsRemover.java

 

Coverage histogram

../../../../img/srcFileCovDistChart9.png
54% of files have more coverage

Code metrics

34
98
33
12
401
248
59
0.6
2.97
2.75
1.79

Classes

Class Line # Actions
DefinitionsRemover 31 35 24 15
0.782608778.3%
DefinitionsRemover.Definition 96 5 4 2
0.880%
DefinitionsRemover.IncompleteDefinition 153 6 3 0
1.0100%
DefinitionsRemover.UnknownDefinition 180 2 2 2
0.550%
DefinitionsRemover.ExternalNameOnlyDefinition 195 2 2 2
0.550%
DefinitionsRemover.FunctionArgumentDefinition 211 4 2 2
0.666666766.7%
DefinitionsRemover.FunctionDefinition 230 5 3 0
1.0100%
DefinitionsRemover.NamedFunctionDefinition 255 2 2 0
1.0100%
DefinitionsRemover.FunctionExpressionDefinition 270 3 2 0
1.0100%
DefinitionsRemover.AssignmentDefinition 287 9 4 0
1.0100%
DefinitionsRemover.ObjectLiteralPropertyDefinition 320 13 7 2
0.8823529588.2%
DefinitionsRemover.VarDefinition 370 12 4 0
1.0100%
 

Contributing tests

This file is covered by 3192 tests. .

Source view

1    /*
2    * Copyright 2009 The Closure Compiler Authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10    * Unless required by applicable law or agreed to in writing, software
11    * distributed under the License is distributed on an "AS IS" BASIS,
12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13    * See the License for the specific language governing permissions and
14    * limitations under the License.
15    */
16   
17    package com.google.javascript.jscomp;
18   
19    import com.google.common.base.Preconditions;
20    import com.google.common.collect.ImmutableSet;
21    import com.google.javascript.rhino.IR;
22    import com.google.javascript.rhino.Node;
23    import com.google.javascript.rhino.Token;
24   
25    import java.util.Set;
26   
27    /**
28    * Models an assignment that defines a variable and the removal of it.
29    *
30    */
 
31    class DefinitionsRemover {
32   
33    /**
34    * @return an {@link Definition} object if the node contains a definition or
35    * {@code null} otherwise.
36    */
 
37  323806 toggle static Definition getDefinition(Node n, boolean isExtern) {
38    // TODO(user): Since we have parent pointers handy. A lot of constructors
39    // can be simplified.
40   
41    // This logic must match #isDefinitionNode
42  323806 Node parent = n.getParent();
43  323806 if (parent == null) {
44  96 return null;
45    }
46   
47  323710 if (NodeUtil.isVarDeclaration(n) && n.hasChildren()) {
48  7617 return new VarDefinition(n, isExtern);
49  316093 } else if (parent.isFunction() && parent.getFirstChild() == n) {
50  26075 if (!NodeUtil.isFunctionExpression(parent)) {
51  13286 return new NamedFunctionDefinition(parent, isExtern);
52  12789 } else if (!n.getString().equals("")) {
53  157 return new FunctionExpressionDefinition(parent, isExtern);
54    }
55  290018 } else if (parent.isAssign() && parent.getFirstChild() == n) {
56  12034 return new AssignmentDefinition(parent, isExtern);
57  277984 } else if (NodeUtil.isObjectLitKey(n, parent)) {
58  262 return new ObjectLiteralPropertyDefinition(parent, n, n.getFirstChild(),
59    isExtern);
60  277722 } else if (parent.isParamList()) {
61  2341 Node function = parent.getParent();
62  2341 return new FunctionArgumentDefinition(function, n, isExtern);
63    }
64  288013 return null;
65    }
66   
67    /**
68    * @return Whether a definition object can be created.
69    */
 
70  95 toggle static boolean isDefinitionNode(Node n) {
71    // This logic must match #getDefinition
72  95 Node parent = n.getParent();
73  95 if (parent == null) {
74  58 return false;
75    }
76   
77  37 if (NodeUtil.isVarDeclaration(n) && n.hasChildren()) {
78  0 return true;
79  37 } else if (parent.isFunction() && parent.getFirstChild() == n) {
80  0 if (!NodeUtil.isFunctionExpression(parent)) {
81  0 return true;
82  0 } else if (!n.getString().equals("")) {
83  0 return true;
84    }
85  37 } else if (parent.isAssign() && parent.getFirstChild() == n) {
86  0 return true;
87  37 } else if (NodeUtil.isObjectLitKey(n, parent)) {
88  4 return true;
89  33 } else if (parent.isParamList()) {
90  0 return true;
91    }
92  33 return false;
93    }
94   
95   
 
96    static abstract class Definition {
97   
98    private final boolean isExtern;
99   
 
100  46781 toggle Definition(boolean isExtern) {
101  46781 this.isExtern = isExtern;
102    }
103   
104    /**
105    * Removes this definition from the AST if it is not an extern.
106    *
107    * This method should not be called on a definition for which isExtern()
108    * is true.
109    */
 
110  63 toggle public void remove() {
111  63 if (!isExtern) {
112  63 performRemove();
113    } else {
114  0 throw new IllegalStateException("Attempt to remove() an extern" +
115    " definition.");
116    }
117    }
118   
119    /**
120    * Subclasses should override to remove the definition from the AST.
121    */
122    protected abstract void performRemove();
123   
124    /**
125    * Variable or property name represented by this definition.
126    * For example, in the case of assignments this method would
127    * return the NAME, GETPROP or GETELEM expression that acts as the
128    * assignment left hand side.
129    *
130    * @return the L-Value associated with this definition.
131    * The node's type is always NAME, GETPROP or GETELEM.
132    */
133    public abstract Node getLValue();
134   
135    /**
136    * Value expression that acts as the right hand side of the
137    * definition statement.
138    */
139    public abstract Node getRValue();
140   
141    /**
142    * Returns true if the definition is an extern.
143    */
 
144  3039 toggle public boolean isExtern() {
145  3039 return isExtern;
146    }
147    }
148   
149    /**
150    * Represents an name-only external definition. The definition's
151    * RHS is missing.
152    */
 
153    abstract static class IncompleteDefinition extends Definition {
154    private static final Set<Integer> ALLOWED_TYPES =
155    ImmutableSet.of(Token.NAME, Token.GETPROP, Token.GETELEM);
156    private final Node lValue;
157   
 
158  13382 toggle IncompleteDefinition(Node lValue, boolean inExterns) {
159  13382 super(inExterns);
160  13382 Preconditions.checkNotNull(lValue);
161  13382 Preconditions.checkArgument(ALLOWED_TYPES.contains(lValue.getType()),
162    "Unexpected lValue type %s", Token.name(lValue.getType()));
163  13382 this.lValue = lValue;
164    }
165   
 
166  8206 toggle @Override
167    public Node getLValue() {
168  8206 return lValue;
169    }
170   
 
171  4267 toggle @Override
172    public Node getRValue() {
173  4267 return null;
174    }
175    }
176   
177    /**
178    * Represents an unknown definition.
179    */
 
180    static final class UnknownDefinition extends IncompleteDefinition {
 
181  5118 toggle UnknownDefinition(Node lValue, boolean inExterns) {
182  5118 super(lValue, inExterns);
183    }
184   
 
185  0 toggle @Override
186    public void performRemove() {
187  0 throw new IllegalArgumentException("Can't remove an UnknownDefinition");
188    }
189    }
190   
191    /**
192    * Represents an name-only external definition. The definition's
193    * RHS is missing.
194    */
 
195    static final class ExternalNameOnlyDefinition extends IncompleteDefinition {
196   
 
197  5923 toggle ExternalNameOnlyDefinition(Node lValue) {
198  5923 super(lValue, true);
199    }
200   
 
201  0 toggle @Override
202    public void performRemove() {
203  0 throw new IllegalArgumentException(
204    "Can't remove external name-only definition");
205    }
206    }
207   
208    /**
209    * Represents a function formal parameter. The definition's RHS is missing.
210    */
 
211    static final class FunctionArgumentDefinition extends IncompleteDefinition {
 
212  2341 toggle FunctionArgumentDefinition(Node function,
213    Node argumentName,
214    boolean inExterns) {
215  2341 super(argumentName, inExterns);
216  2341 Preconditions.checkArgument(function.isFunction());
217  2341 Preconditions.checkArgument(argumentName.isName());
218    }
219   
 
220  0 toggle @Override
221    public void performRemove() {
222  0 throw new IllegalArgumentException(
223    "Can't remove a FunctionArgumentDefinition");
224    }
225    }
226   
227    /**
228    * Represents a function declaration or function expression.
229    */
 
230    abstract static class FunctionDefinition extends Definition {
231   
232    protected final Node function;
233   
 
234  13476 toggle FunctionDefinition(Node node, boolean inExterns) {
235  13476 super(inExterns);
236  13476 Preconditions.checkArgument(node.isFunction());
237  13476 function = node;
238    }
239   
 
240  22548 toggle @Override
241    public Node getLValue() {
242  22548 return function.getFirstChild();
243    }
244   
 
245  18642 toggle @Override
246    public Node getRValue() {
247  18642 return function;
248    }
249    }
250   
251    /**
252    * Represents a function declaration without assignment node such as
253    * {@code function foo()}.
254    */
 
255    static final class NamedFunctionDefinition extends FunctionDefinition {
 
256  13298 toggle NamedFunctionDefinition(Node node, boolean inExterns) {
257  13298 super(node, inExterns);
258    }
259   
 
260  12 toggle @Override
261    public void performRemove() {
262  12 function.detachFromParent();
263    }
264    }
265   
266    /**
267    * Represents a function expression that acts as a RHS. The defined
268    * name is only reachable from within the function.
269    */
 
270    static final class FunctionExpressionDefinition extends FunctionDefinition {
 
271  178 toggle FunctionExpressionDefinition(Node node, boolean inExterns) {
272  178 super(node, inExterns);
273  178 Preconditions.checkArgument(
274    NodeUtil.isFunctionExpression(node));
275    }
276   
 
277  3 toggle @Override
278    public void performRemove() {
279    // replace internal name with ""
280  3 function.replaceChild(function.getFirstChild(), IR.name(""));
281    }
282    }
283   
284    /**
285    * Represents a declaration within an assignment.
286    */
 
287    static final class AssignmentDefinition extends Definition {
288    private final Node assignment;
289   
 
290  12044 toggle AssignmentDefinition(Node node, boolean inExterns) {
291  12044 super(inExterns);
292  12044 Preconditions.checkArgument(node.isAssign());
293  12044 assignment = node;
294    }
295   
 
296  21 toggle @Override
297    public void performRemove() {
298    // A simple assignment. foo = bar() -> bar();
299  21 Node parent = assignment.getParent();
300  21 Node last = assignment.getLastChild();
301  21 assignment.removeChild(last);
302  21 parent.replaceChild(assignment, last);
303    }
304   
 
305  16879 toggle @Override
306    public Node getLValue() {
307  16879 return assignment.getFirstChild();
308    }
309   
 
310  13074 toggle @Override
311    public Node getRValue() {
312  13074 return assignment.getLastChild();
313    }
314    }
315   
316    /**
317    * Represents member declarations using a object literal.
318    * Example: var x = { e : function() { } };
319    */
 
320    static final class ObjectLiteralPropertyDefinition extends Definition {
321   
322    private final Node literal;
323    private final Node name;
324    private final Node value;
325   
 
326  262 toggle ObjectLiteralPropertyDefinition(Node lit, Node name, Node value,
327    boolean isExtern) {
328  262 super(isExtern);
329   
330  262 this.literal = lit;
331  262 this.name = name;
332  262 this.value = value;
333    }
334   
 
335  9 toggle @Override
336    public void performRemove() {
337  9 literal.removeChild(name);
338    }
339   
 
340  445 toggle @Override
341    public Node getLValue() {
342    // TODO(user) revisit: object literal definitions are an example
343    // of definitions whose LHS doesn't correspond to a node that
344    // exists in the AST. We will have to change the return type of
345    // getLValue sooner or later in order to provide this added
346    // flexibility.
347   
348  445 switch (name.getType()) {
349  25 case Token.SETTER_DEF:
350  28 case Token.GETTER_DEF:
351  392 case Token.STRING_KEY:
352    // TODO(johnlenz): return a GETELEM for quoted strings.
353  445 return IR.getprop(
354    IR.objectlit(),
355    IR.string(name.getString()));
356  0 default:
357  0 throw new IllegalStateException("unexpected");
358    }
359    }
360   
 
361  381 toggle @Override
362    public Node getRValue() {
363  381 return value;
364    }
365    }
366   
367    /**
368    * Represents a VAR declaration with an assignment.
369    */
 
370    static final class VarDefinition extends Definition {
371    private final Node name;
 
372  7617 toggle VarDefinition(Node node, boolean inExterns) {
373  7617 super(inExterns);
374  7617 Preconditions.checkArgument(NodeUtil.isVarDeclaration(node));
375  7617 Preconditions.checkArgument(node.hasChildren(),
376    "VAR Declaration of %sshould be assigned a value.", node.getString());
377  7617 name = node;
378    }
379   
 
380  18 toggle @Override
381    public void performRemove() {
382  18 Node var = name.getParent();
383  18 Preconditions.checkState(var.getFirstChild() == var.getLastChild(),
384    "AST should be normalized first");
385  18 Node parent = var.getParent();
386  18 Node rValue = name.removeFirstChild();
387  18 Preconditions.checkState(!parent.isFor());
388  18 parent.replaceChild(var, NodeUtil.newExpr(rValue));
389    }
390   
 
391  15864 toggle @Override
392    public Node getLValue() {
393  15864 return name;
394    }
395   
 
396  9175 toggle @Override
397    public Node getRValue() {
398  9175 return name.getFirstChild();
399    }
400    }
401    }